<?php

namespace Largezhou\Admin\Table;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Support\Collection;
use Largezhou\Admin\Components\Component;
use Largezhou\Admin\Traits\HeaderTools;

class Table extends Component
{
    use HeaderTools;

    /**
     * @var Model
     */
    protected $model;
    protected $columns;
    protected $data = null;
    protected $pagination = null;

    protected $pageName = '_page';
    protected $perPageName = '_per_page';
    protected $pageSizes = [15, 20, 30, 50, 100];
    protected $defaultPerPage = 15;

    protected $ajaxRoute;

    /**
     * @param Model $model 模型实例或者模型类名
     */
    public function __construct(Model $model)
    {
        $this->model = $model;

        $this->columns = new Collection();

        $this->setupDefaultTools();
    }

    protected function setupDefaultTools()
    {
        $this->headerTool($this->toolManager()->link('添加', $this->ajaxRoute().'/create', 'primary'));
    }

    /**
     * 添加一列到表格中
     *
     * @param string $name
     * @param string $label
     *
     * @return Column
     */
    public function column(string $name, string $label = '')
    {
        $relationName = $relationColumn = '';

        if (strpos($name, '.') !== false) {
            list($relationName, $relationColumn) = explode('.', $name);

            $relation = $this->model->$relationName();

            $label = empty($label) ? ucfirst($relationColumn) : $label;

            $name = snake_case($relationName).'.'.$relationColumn;
        }

        $column = new Column($name, $label);

        $this->columns->push($column);

        if (isset($relation) && $relation instanceof Relation) {
            $this->model = $this->model->with($relationName);
            $column->setRelation($relationName, $relationColumn);
        }

        return $column;
    }

    /**
     * 获取所有列,或者批量设置列.
     *
     * @example
     * 1.columns(['name' => 'Name', 'email' => 'Email' ...]);
     * 2.columns('name', 'email' ...)
     *
     * @param array $columns
     *
     * @return array|$this
     */
    public function columns($columns = [])
    {
        if (func_num_args() == 0) {
            return $this->columns;
        }

        if (func_num_args() == 1 && is_array($columns)) {
            foreach ($columns as $column => $label) {
                $this->column($column, $label);
            }

            return $this;
        }

        foreach (func_get_args() as $column) {
            $this->column($column);
        }

        return $this;
    }

    public function data()
    {
        if (is_null($this->data)) {
            $this->buildData();
        }

        return $this->data;
    }

    protected function buildData()
    {
        list($perPage, $page) = $this->getSafePageOptions();

        $paginator = $this
            ->model
            ->paginate(
                $perPage,
                ['*'],
                $this->pageName,
                $page
            )
            ->toArray();

        $this->data = array_get($paginator, 'data');
        $this->appendActionsColumn();

        $columnNames = [];
        $this->columns->each(function (Column $column) use (&$columnNames) {
            $this->data = $column->handleValue($this->data);

            $columnNames[] = $column->name();
        });

        $this->data = array_map(function ($data) use ($columnNames) {
            $data = array_only($data, $columnNames);
            foreach ($data as $key => $value) {
                if (strpos($key, '.') !== false) {
                    array_set($data, $key, $value);
                    unset($data[$key]);
                }
            }

            return $data;
        }, $this->data);

        $this->pagination = array_only($paginator, [
            'current_page', 'per_page', 'total',
        ]);
    }

    protected function appendActionsColumn()
    {
        $this->column('_action', '操作')
             ->display(function ($value, $row, $index) {
                 return [
                     $this->toolManager()->link('编辑', $this->ajaxRoute().'/'.$row['id'].'/edit'),
                     $this->toolManager()->tableDelete($this->ajaxRoute().'/'.$row['id']),
                 ];
             });
    }

    protected function getSafePageOptions()
    {
        $request = app('request');

        $perPage = (int) $request->get($this->perPageName);
        $page = (int) $request->get($this->pageName);

        if ($perPage <= 0) {
            $perPage = array_first($this->pageSizes) ?? $this->defaultPerPage;
        }

        if ($page <= 0) {
            $page = 1;
        } else {
            $lastPage = (int) ceil($this->model->count() / $perPage);

            if ($page > $lastPage) {
                $page = $lastPage;
            }
        }

        return [$perPage, $page];
    }

    public function pagination()
    {
        if (is_null($this->pagination)) {
            $this->buildData();
        }

        return $this->pagination + ['page_sizes' => $this->pageSizes];
    }

    public function ajaxRoute($path = null)
    {
        if (!empty($path)) {
            $this->ajaxRoute = $path;

            return $this;
        }

        if (!empty($this->ajaxRoute)) {
            return $this->ajaxRoute;
        }

        return route_path($path);
    }

    public function variables()
    {
        return [
            'component' => $this->component(),
            'props'     => [
                'columns'     => $this->columns(),
                'data'        => $this->data(),
                'page'        => $this->pagination(),
                'headerTools' => $this->headerTools(),
            ],
        ];
    }
}
